package interceptor

import (
	"context"
	"encoding/json"
	"strings"
	"time"

	"gitee.com/krio/helper/logger"
	"google.golang.org/grpc"
	"google.golang.org/grpc/peer"
)

type AccessLog struct {
	Method   string // 请求方法
	Start    string // 访问时间
	Cost     int64  // 耗时
	ClientIP string // 客户端的IP
	Request  string // 入参
	Response string // 返回值
}

func GrpcLogger(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	// 前置处理逻辑
	var (
		resp interface{}
		err  error
		ts   = time.Now()
	)
	accessLog := &AccessLog{
		Method: info.FullMethod[strings.LastIndex(info.FullMethod, ".")+1:],
		Start:  ts.Local().Format(time.RFC3339),
	}
	if peer, ok := peer.FromContext(ctx); ok {
		accessLog.ClientIP = peer.Addr.String()
	}
	if str, ok := toString(req); ok {
		accessLog.Request = str
	}

	// 后置处理逻辑
	defer func() {
		if str, ok := toString(resp); ok {
			accessLog.Response = str
		}

		// 日志记录
		logger.WithContext(ctx).Infow("grpc access log",
			"method", accessLog.Method,
			"start", accessLog.Start,
			"cost(ms)", time.Since(ts).Milliseconds(),
			"client_ip", accessLog.ClientIP,
			"request", accessLog.Request,
			"response", accessLog.Response,
		)
	}()
	// 完成RPC服务的正常执行
	resp, err = handler(ctx, req)
	return resp, err
}

func toString(data interface{}) (string, bool) {
	if data == nil {
		return "", false
	}

	value, err := json.Marshal(data)
	if err == nil {
		return string(value), true
	}

	return string(value), true
}
